#!/usr/bin/env node
var fs                  = require('fs');
var readline            = require('readline');
var when                = require('when');
var pipeline            = require('when/pipeline');
var utils               = require('./utils');
var path                = require('path');
var Dictionary          = require('./dictionary').Dictionary;
var FrequencySampler    = require('./fqsampler').FrequencySampler;
var dotEvery            = 5000;

exports.JSONify = ( function() {

    function JSONify(languageName, parser, config, params) {
        this.languageName       = languageName;
        this.params             = params;
        this.parser             = parser;
        this.config             = config;
        this.out                = new Dictionary(config.get().templates);
        this.dependencies       = [module.filename]
                                  .concat(this.out.dependencies)
                                  .concat(this.parser.dependencies);
        this.rawEntriesNumber   = 0;
    }

    JSONify.prototype.process = function() {
        var self = this;
        return pipeline([
            function() {return self.parser.do();},
            function(entries) {
                if (fs.existsSync(self.params.sampleFile)) {
                    console.log("Wiktionary : sample file for language '"+self.languageName+"' found :'"+self.params.sampleFile+"' - sampling...");
                    return new FrequencySampler(entries, self.params.sampleFile).do();
                }
            },
            function() {
                var lines = 0;
                console.log("\nJSONify : Processing parsed entries...");
                for (var entry in self.parser.entries) {
                    self.rawEntriesNumber++;
                    self.out.process(entry, self.parser.entries[entry]);
                    if (lines++%dotEvery == 0) {
                        process.stdout.write(".");
                    }
                }
                var entriesNo = 0;
                var ourArray = self.out.finish(function() {
                    if (entriesNo++%dotEvery == 0) {
                        process.stdout.write(".");
                    }
                });
                console.log("\nJSONify : Parsed entries processed");
                return self.dump(self.params.output, self.config.get(), ourArray);
            },
        ]);
    }


    JSONify.prototype.dump = function(folder, config, dictionaryArray) {
        console.log("\nJSONify : Dumping entries to '"+folder+"'");
        if (fs.existsSync(folder)) {
            console.log("JSONify : '"+folder+"' already exists, purging.");
            utils.rmdirSyncForce(folder);
        }
        fs.mkdirSync(folder);

        dictionaryArray.sort(function(a,b) {
            var result = b.properties.hits - a.properties.hits;
            if (result == 0) {
                //if equal, randomise order
                result = getHash(b.entry, 10)-getHash(a.entry, 10);
            }
            return result;
        });

        var manifest = {
            timestamp   : new Date().getTime(),
            name        : this.languageName,
            cuts        : {},
            stats       : {
                rawEntries      : this.rawEntriesNumber,
                finalEntries    : dictionaryArray.length,
                errors          : {
                    parsing     : this.parser.failures,
                    processing  : this.out.failures,
                    missing     : this.out.missing,
                    orphaned    : this.out.orphans.length
                }
            }
        };

        console.log("JSONify : Writing cuts");
        for (var cut in config.cuts) {
            var cutFolder = folder+"/"+cut;
            dump(dictionaryArray, cutFolder, config.cuts[cut]);

            manifest.cuts[cut] = {parcels : []};
            var filesWrote = fs.readdirSync(cutFolder);
            for (var i = 0; i < filesWrote.length; i++) {
                var fileName = cut+"/"+path.basename(filesWrote[i]);
                manifest.cuts[cut].parcels.push({ path : fileName });
            }
        }

        console.log("\nJSONify : Dumped "+dictionaryArray.length+" entries to '"+folder+"'");
        fs.appendFileSync(folder+"/manifest.json", JSON.stringify(manifest, undefined, 2));
        return {
            folder      : path.basename(folder),
            manifest    : "manifest.json"
        };
    }


    function dump(outArray, folder, config) {
        console.log("\nJSONify : writing folder '"+folder+"'");
        if (!fs.existsSync(folder)) {
            fs.mkdirSync(folder);
        }
        var fileNameRoot = "data";
        var fileIndex = 0;

        var entriesWrote = 0;
        var file = undefined;

        if (!config.parcelsize) {
            config.parcelsize = outArray.length;
        }

        for (var i = 0; i < outArray.length; i++) {
            var write = true;
            var arrayElem = outArray[i];

            if (config.types) {
                write = false;
                for (var t = 0; t < config.types.length; t++) {
                    var type = config.types[t];
                    if (type in arrayElem.properties.variants) {
                        write = true;
                        break;
                    }
                }
            }

            if (write && config.length) {
                if (config.length.min &&
                    config.length.min >= arrayElem.entry.length) {
                    write = false;
                }
                if (config.length.max &&
                    config.length.max <= arrayElem.entry.length) {
                    write = false;
                }
            }

            if (write) {
                var separator = ",\n";
                if (entriesWrote%config.parcelsize == 0) {
                    if (file) {
                        //close previous file
                        fs.appendFileSync(file, '\n}');
                    }

                    //open new file
                    file = folder+"/"+fileNameRoot+getLeadZeroNumber(fileIndex++, 8)+".json";
                    fs.appendFileSync(file, "{\n");
                    separator = "";
                }

                fs.appendFileSync(file, separator+"\""+arrayElem.entry+"\" : "+JSON.stringify(arrayElem.properties, undefined, 2));

                if (entriesWrote++%dotEvery == 0) {
                    process.stdout.write(".");
                }
            }
        }
        if (file) {
            //close previous file
            fs.appendFileSync(file, '\n}');
        }
    }

    function getLeadZeroNumber(number, length) {
        var s = number+"";
        while (s.length < length) s = "0" + s;
        return s;
    }

    function openNewDumpFile(folder, nameRoot, index) {
        var file = folder+"/"+nameRoot+getLeadZeroNumber(index++, 8)+".json";
        fs.appendFileSync(file, "{\n");
    }

    function getHash(string, resolution) {
        var hash = 0;
        for (var i = 0; i < string.length; i++) {
            hash += string.charCodeAt(i);
        }
        return hash%resolution;
    }

    return JSONify;
})();


